package com.yexx.starter.security.pwd;

import com.yexx.core.exception.CommonException;
import com.yexx.starter.security.basic.SecurityUserDetailsService;
import com.yexx.starter.security.basic.constant.SecurityConstants;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Description: 账户密码登录provider
 *
 * @author: zuomin (myleszelic@outlook.com)
 * @date: 2020/11/03 10:56
 */
public class PwdAuthenticationProvider implements AuthenticationProvider {

    private SecurityUserDetailsService userDetailsService;

    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        PwdAuthenticationToken authenticationToken = (PwdAuthenticationToken) authentication;

        //调用自定义的userDetailsService认证
        //判断账户是否存在
        UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
        if (user == null) {
            // 捕获到的异常会交给 {@link BasicLoginFilter#unsuccessfulAuthentication(...) }
            throw new InternalAuthenticationServiceException("用户名或者密码错误");
        }
        //判断密码是否正确
        if (!passwordEncoder.matches(authentication.getCredentials().toString(), user.getPassword())) {
            // 捕获到的异常会交给 {@link BasicLoginFilter#unsuccessfulAuthentication(...) }
            throw new InternalAuthenticationServiceException("用户名或者密码错误");
        }

        Boolean isBind = userDetailsService.checkBindDevice((String) authenticationToken.getPrincipal(), authenticationToken.getDeviceUuid());
        if (!isBind) {
            throw new CommonException(SecurityConstants.RETURN_CODE.DEVICE_UNBIND, "device unbind");
        }

        //重新构建UsernamePasswordAuthenticationToken（已认证）
        UsernamePasswordAuthenticationToken authenticationResult = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());

        return authenticationResult;
    }

    /**
     * 只有Authentication为PwdAuthenticationToken使用此Provider认证
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return PwdAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setSecurityUserService(SecurityUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

}
